#pragma once
#include <sys/wait.h>
#include <pthread.h>
#include <functional>
#include "Common.hpp"
#include "Log.hpp"
#include "InetAddr.hpp"
#include "ThreadPool.hpp"

// 服务器端往往禁止拷贝
using namespace ThreadPoolModule;
using namespace LogModule;
using namespace InetAddrModule;

// 回调函数类型
using func_t = std::function<std::string(const std::string &, InetAddr &)>;

const static int backlog = 8;
const static int defaultsockfd = -1;

class TcpServer : public NoCopy
{
public:
    TcpServer(uint16_t port, func_t func): _port(port), _listensockfd(defaultsockfd),_isrunning(false),_func(func)
    {}

    void Init()
    {
        // 1、创建套接字
        _listensockfd = socket(AF_INET, SOCK_STREAM, 0);
        if (_listensockfd < 0)
        {
            LOG(LogLevel::FATAL) << "socket error";
            exit(SOCKET_ERR);
        }
        LOG(LogLevel::INFO) << "socket success" << _listensockfd; // 3

        // 2、bind众所周知的端口号
        InetAddr local(_port);
        int n = bind(_listensockfd, local.NetAddrPtr(), local.NetAddrLen());
        if (n < 0)
        {
            LOG(LogLevel::FATAL) << "bind error";
            exit(BIND_ERR);
        }
        LOG(LogLevel::INFO) << "bind success: " << _listensockfd; // 3
        // 3、设置sock状态为listen
        n = listen(_listensockfd, backlog);
        if (n < 0)
        {
            LOG(LogLevel::FATAL) << "listen error";
            exit(LISTEN_ERR);
        }
        LOG(LogLevel::INFO) << "listen success: " << _listensockfd; // 3
    }

    class ThreadData
    {
        public:
        ThreadData(int fd, InetAddr& ar, TcpServer* s) :sockfd(fd), addr(ar), tsvr(s){}
        //成员变量设置为public，以便访问   
            int sockfd;
            InetAddr addr;
            TcpServer *tsvr;
    };
    ~TcpServer() {}

    //长服务：多进程多线程
   void Service(int sockfd, InetAddr& peer)
   {
        char buffer[1024];
        while(true)
        {
            //1、先读取数据
            //n > 0 读取成功 n == 0 对端把链接关闭，读到文件结尾 n < 0读取失败
            ssize_t n = read(sockfd, buffer, sizeof(buffer) - 1);
            if(n > 0)
            {
                //buffer是一个命令字符串
                buffer[n] = '\0';
                LOG(LogLevel::INFO) << peer.StringAddr() << "#" << buffer;
                
                std::string echo_string = _func(buffer, peer);

                //2、写回数据
                write(sockfd, echo_string.c_str(), echo_string.size());
            }
            else if (n == 0)
            {
                LOG(LogLevel::DEBUG) << peer.StringAddr() << " 退出了...";
                close(sockfd);
                break;
            }
            else
            {
                LOG(LogLevel::DEBUG) << peer.StringAddr() << " 异常...";
                close(sockfd);
                break;
            }
        }
   }

   static void *Routine(void *args)
   {
       pthread_detach(pthread_self());
       ThreadData *td = static_cast<ThreadData *>(args);
       td->tsvr->Service(td->sockfd, td->addr);
       delete td;
       return nullptr;
   }

   void Run()
   {
     _isrunning = true;
     while(_isrunning)
     {
        //1、获取新连接
        struct sockaddr_in peer;
        socklen_t len = sizeof(sockaddr_in);
        int sockfd = accept(_listensockfd, CONV(peer), &len); //sockfd用于提供服务
        if(sockfd < 0)
        {
            LOG(LogLevel::WARNING) << "accept error";
            continue;
        }

        InetAddr addr(peer);
        LOG(LogLevel::INFO) << "accept success, peer addr : " << addr.StringAddr();
        //多线程版本
        ThreadData* td = new ThreadData(sockfd, addr, this);
        pthread_t tid;
        pthread_create(&tid, nullptr, Routine, td);
     }
     _isrunning = false;
   }

private:
    uint16_t _port;
    int _listensockfd; // 监听套接字
    bool _isrunning;
    func_t _func; // 设置回调方法
};
